package server

import (
	"archive/zip"
	"github.com/phprao/ColorOutput"
	"io"
	"log"
	"mime"
	"net"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
)

// GetExeDir 用于获取当前程序所在目录
func GetExeDir() string {
	ex, err := os.Executable()
	if err != nil {
		panic(err)
	}
	exPath := filepath.Dir(ex)
	return exPath
}

// GetFileContentType 用于获取文件的MimeType
func GetFileContentType(filename string) string {

	var res string
	ext := path.Ext(filename)
	if ext != "" {
		res = mime.TypeByExtension(ext)
	}
	if res == "" {
		out, err := os.Open(filename)
		if err != nil {
			return ""
		}
		buffer := make([]byte, 512)
		_, err = out.Read(buffer)
		if err != nil {
			return ""
		}
		res = http.DetectContentType(buffer)
	}
	return res
}

// PrintInterfaces 打印服务器中的网卡及其地址
func PrintInterfaces(port int) {
	println("服务器正在启动，你或许可以通过以下地址访问浏览页面：")
	interfaces, err := net.Interfaces()
	if err != nil {
		return
	}
	nameIPS := map[string]string{}
	var names []string
	for _, i := range interfaces {
		name := i.Name
		addrs, err := i.Addrs()
		if err != nil {
			continue
		}
		// handle err
		for _, addr := range addrs {
			var (
				ip net.IP
			)
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			//屏蔽IPV6地址
			if strings.Index(ip.String(), ":") != -1 {
				continue
			}
			println(name, ":\t", "http://"+ip.String()+":"+strconv.Itoa(port)+"/view")
			names = append(names, name)
			nameIPS[name] = ip.String()
		}
	}
	sort.Strings(names)
	if len(names) == 0 {
		println("没有找到任何网卡信息")
		return
	}
}

// buildZip 将一个文件夹压缩成zip包，参考：https://learnku.com/articles/23434/golang-learning-notes-five-archivezip-to-achieve-compression-and-decompression
func buildZip(folder string, out string) error {
	// 创建准备写入的文件
	fw, err := os.Create(out)
	defer fw.Close()
	if err != nil {
		return err
	}

	// 通过 fw 来创建 zip.Write
	zw := zip.NewWriter(fw)
	defer func() {
		// 检测一下是否成功关闭
		if err := zw.Close(); err != nil {
			log.Fatalln(err)
		}
	}()

	// 下面来将文件写入 zw ，因为有可能会有很多个目录及文件，所以递归处理
	return filepath.Walk(folder, func(path string, fi os.FileInfo, errBack error) (err error) {
		if errBack != nil {
			return errBack
		}

		// 通过文件信息，创建 zip 的文件信息
		fh, err := zip.FileInfoHeader(fi)
		if err != nil {
			return err
		}

		rel, err := filepath.Rel(folder, path)
		if err != nil {
			return err
		}

		// 替换文件信息中的文件名
		fh.Name = strings.TrimPrefix(rel, string(filepath.Separator))

		// 这步开始没有加，会发现解压的时候说它不是个目录
		if fi.IsDir() {
			fh.Name += "/"
		}

		// 写入文件信息，并返回一个 Write 结构
		w, err := zw.CreateHeader(fh)
		if err != nil {
			return err
		}

		// 检测，如果不是标准文件就只写入头信息，不写入文件数据到 w
		// 如目录，也没有数据需要写
		if !fh.Mode().IsRegular() {
			return nil
		}

		// 打开要压缩的文件
		fr, err := os.Open(path)
		defer fr.Close()
		if err != nil {
			return err
		}

		// 将打开的文件 Copy 到 w
		_, err = io.Copy(w, fr)
		if err != nil {
			return err
		}
		return nil
	})
}

func IsExist(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}
	return true
}

func IsDir(path string) bool {
	stat, err := os.Stat(path)
	if err != nil {
		return false
	}
	return stat.IsDir()
}

func IsSubDir(dir string, sub string) bool {
	dir = filepath.Dir(filepath.Join(dir, "/"))
	sub = filepath.Dir(filepath.Join(sub, "/"))

	if filepath.IsAbs(dir) && filepath.IsAbs(sub) {
		if len(sub) < len(dir) || sub[:len(dir)] != dir {
			return false
		}
	} else {
		return false
	}
	return true
}
func PrintWarring(message string) {
	ColorOutput.Colorful.
		WithBackColor("black").
		WithFrontColor("red").
		Println(message)
	return
}
